﻿#region Copyright (c) 2000-2008 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{       AgDataGrid                                 }
{                                                                   }
{       Copyright (c) 2000-2008 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2008 Developer Express Inc.

using System.Collections;
using System.Collections.Generic;
using System;
using System.Reflection;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
namespace DevExpress.AgDataGrid.Data.Helpers {
	public class DataColumnSortInfo {
		DataColumn column;
		ColumnSortOrder sortOrder;
		public DataColumnSortInfo(DataColumn column) : this(column, ColumnSortOrder.Ascending) { }
		public DataColumnSortInfo(DataColumn column, ColumnSortOrder sortOrder) {
			this.column = column;
			this.sortOrder = sortOrder;
			if(Column == null) throw new ArgumentNullException("column");
		}
		public DataColumn Column { get { return column; } }
		public ColumnSortOrder SortOrder {
			get { return sortOrder; }
		}
		public bool IsEquals(DataColumnSortInfo info) {
			if(info == null) return false;
			return info.Column == Column && info.SortOrder == SortOrder;
		}
	}
	public class DataColumnSortInfoCollection : ObservableCollection<DataColumnSortInfo> {
		int groupCount;
		public DataColumnSortInfoCollection() { }
		public DataColumnSortInfo this[DataColumn column] {
			get {
				foreach(DataColumnSortInfo sortInfo in Items) {
					if(sortInfo.Column == column) return sortInfo;
				}
				return null;
			}
		}
		public int GroupCount {
			get { return Math.Min(Count, groupCount); }
			set {
				int oldGroupCount = GroupCount;
				SetGroupCountCore(value);
				if(oldGroupCount != GroupCount)
					OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
			}
		}
		public void AddRange(params DataColumnSortInfo[] sortInfos) {
			AddRangeCore(sortInfos);
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
		}		
		public void AddRange(int groupCount, params DataColumnSortInfo[] sortInfos) {
			AddRangeCore(sortInfos);
			SetGroupCountCore(groupCount);
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
		}
		public void ClearAddRange(params DataColumnSortInfo[] sortInfos) {			
			Items.Clear();
			AddRange(sortInfos);
		}
		public void ClearAddRange(int groupCount, params DataColumnSortInfo[] sortInfos) {
			Items.Clear();
			AddRange(groupCount, sortInfos);
		}
		protected override void InsertItem(int index, DataColumnSortInfo item) {
			ValidateItem(item);
			base.InsertItem(index, item);
		}
		protected void AddRangeCore(DataColumnSortInfo[] sortInfos) {
			foreach(DataColumnSortInfo sortInfo in sortInfos) {
				ValidateItem(sortInfo);
				Items.Add(sortInfo);
			}
		}
		protected void SetGroupCountCore(int value) {
			if(value < 0) value = 0;
			if(groupCount == value) return;
			groupCount = value;
		}
		protected virtual void ValidateItem(DataColumnSortInfo item) {
			if(this[item.Column] != null) throw new ArgumentException("column sorting already in the list.");
			if(item.SortOrder == ColumnSortOrder.None) throw new ArgumentException("SortOrder is None");
		}
	}
	public class GroupRowInfo {
		public int Level;
		public bool Expanded;
		public GroupRowInfo ParentGroup;
		public int ChildControllerRow;
		public int ChildControllerRowCount;
		public int Index;
		Dictionary<SummaryItem, object> summary;
		public GroupRowInfo() : this(0, 0, null) { }
		public GroupRowInfo(int level, int childControllerRow, GroupRowInfo parentGroup) {
			this.Level = level;
			this.ChildControllerRow = childControllerRow;
			this.ChildControllerRowCount = 1;
			this.Expanded = false;
			this.ParentGroup = parentGroup;
		}
		public int Handle { get { return GroupIndexToHandle(Index); } }
		public bool IsVisible {
			get {
				GroupRowInfo groupRow = ParentGroup;
				if(groupRow == null) return true;
				while(groupRow != null) {
					if(!groupRow.Expanded) return false;
					groupRow = groupRow.ParentGroup;
				}
				return true;
			}
		}
		public int GetVisibleIndexOfControllerRow(int controllerRow) {
			if(!ContainsControllerRow(controllerRow)) return -1;
			return controllerRow - ChildControllerRow;
		}
		public bool ContainsControllerRow(int controllerRow) {
			return controllerRow >= ChildControllerRow && (controllerRow < ChildControllerRow + ChildControllerRowCount);
		}
		public static bool IsGroupRowHandle(int controllerRow) {
			return (controllerRow < 0 && controllerRow != DataController.InvalidRow);
		}
		public static int GroupIndexToHandle(int groupIndex) { return -1 - groupIndex; }
		public static int HandleToGroupIndex(int handle) {
			if(handle == DataController.InvalidRow) return DataController.InvalidRow;
			return Math.Abs(handle) - 1;
		}
		internal GroupRowInfo GetParentGroupAtLevel(int level) {
			GroupRowInfo group = this;
			while(group != null && group.Level != level) {
				group = group.ParentGroup;
			}
			return group;
		}
		protected internal Dictionary<SummaryItem, object> Summary { 
			get {
				if(summary == null)
					summary = new Dictionary<SummaryItem, object>();
				return summary; 
			} 
		}
		public object GetSummaryValue(SummaryItem item) {
			if(!Summary.ContainsKey(item)) return null;
			return Summary[item];
		}
		public void SetSummaryValue(SummaryItem item, object value) {
			if(!Summary.ContainsKey(item))
				Summary.Add(item, value);
			else
				Summary[item] = value;
		}
		public void ClearSummaryItem(SummaryItem item) {
			if(!Summary.ContainsKey(item)) return;
			Summary.Remove(item);
		}
		public void ClearSummary() {
			Summary.Clear();
		}		
	}
	public class GroupRowInfoCollection : Collection<GroupRowInfo> {
		DataColumnSortInfoCollection sortInfo;
		protected DataColumnSortInfoCollection SortInfo { get { return sortInfo; } }
		public int LevelCount { get { return SortInfo.GroupCount; } }
		public bool IsLastLevel(GroupRowInfo groupRow) { return groupRow.Level + 1 == LevelCount; }
		public GroupRowInfoCollection(DataColumnSortInfoCollection sortInfo) {
			this.sortInfo = sortInfo;
		}
		public GroupRowInfo Add(int level, int childControllerRow, GroupRowInfo parentGroup) {
			GroupRowInfo groupRow = CreateGroupRowInfo(level, childControllerRow, parentGroup);
			Items.Add(groupRow);
			return groupRow;
		}
		protected virtual GroupRowInfo CreateGroupRowInfo(int level, int childControllerRow, GroupRowInfo parentGroupRow) {
			return new GroupRowInfo(level, childControllerRow, parentGroupRow);
		}
		public void UpdateIndexes() {
			for(int i = Count - 1; i >= 0; i--)
				this[i].Index = i;
		}
		public int GetTotalChildrenGroupCount(GroupRowInfo groupRow) {
			if(groupRow == null) return 0;
			int count = 0;
			for(int i = groupRow.Index + 1; i < Count; i++) {
				if(this[i].Level <= groupRow.Level) break;
				count ++;
			}
			return count;
		}
		public bool ChangeExpanded(int groupRowHandle, bool expanded, bool recursive) {
			GroupRowInfo groupRow = GetGroupRowInfoByHandle(groupRowHandle);
			if(groupRow == null) return false;
			bool hasChanges = ChangeGroupRowExpanded(groupRow, expanded);
			if(recursive)
				hasChanges |= ChangeChildExpanded(groupRow, expanded);
			return hasChanges;
		}
		protected bool ChangeGroupRowExpanded(GroupRowInfo groupRow, bool expanded) {
			if(groupRow.Expanded == expanded) return false;
			groupRow.Expanded = expanded;
			return true;
		}
		public bool ChangeAllExpanded(bool expanded) {
			bool hasChanges = false;
			for(int i = Count - 1; i >= 0; i--) {
				hasChanges |= ChangeGroupRowExpanded(this[i], expanded);
			}
			return hasChanges;
		}
		public bool ChangeChildExpanded(GroupRowInfo groupRow, bool expanded) {
			if(IsLastLevel(groupRow)) return false;
			bool hasChanges = false;
			for(int i = GetTotalChildrenGroupCount(groupRow); i > 0; i--) {
				hasChanges |= ChangeGroupRowExpanded(this[groupRow.Index + i], expanded);
			}
			return hasChanges;
		}
		public GroupRowInfo GetGroupRowInfoByHandle(int groupRowHandle) {
			int groupRowIndex = GroupRowInfo.HandleToGroupIndex(groupRowHandle);
			if(groupRowIndex < 0 || groupRowIndex >= Count) return null;
			return this[groupRowIndex];
		}
		public int GetControllerRowLevel(int controllerRow) {			
			GroupRowInfo group = GetGroupRowInfoByControllerRowHandle(controllerRow);
			if(group == null) return -1;
			if(GroupRowInfo.IsGroupRowHandle(controllerRow)) return group.Level;
			return group.Level + 1;
		}
		public GroupRowInfo GetGroupRowInfoByControllerRowHandle(int controllerRow) {
			if(GroupRowInfo.IsGroupRowHandle(controllerRow))
				return GetGroupRowInfoByHandle(controllerRow);
			for(int i = Count - 1; i >= 0; i--) {
				GroupRowInfo groupRow = this[i];
				if(IsLastLevel(groupRow) && groupRow.ContainsControllerRow(controllerRow)) {
					return groupRow;
				}
			}
			return null;
		}
	}
	public class VisibleIndexCollection : List<int> {
		GroupRowInfoCollection groupInfo;
		protected GroupRowInfoCollection GroupInfo { get { return groupInfo; } }
		public VisibleIndexCollection(GroupRowInfoCollection groupInfo) {
			this.groupInfo = groupInfo;
		}
		public void BuildVisibleIndexes(bool expandAll) {
			Clear();
			foreach(GroupRowInfo groupRow in GroupInfo) {
				if(groupRow.Level == 0) 
					BuildVisibleIndexesCore(groupRow, expandAll, true);
			}
		}
		public void BuildVisibleIndexes(GroupRowInfo groupRow, bool expandAll) {
			BuildVisibleIndexesCore(groupRow, expandAll, true);
		}
		protected void BuildVisibleIndexesCore(GroupRowInfo groupRow, bool expandAll, bool expanded) {
			if(expanded) Add(groupRow.Handle);
			if(groupRow.Expanded || expandAll) {
				if(GroupInfo.IsLastLevel(groupRow)) {
					AddVisibleDataRows(groupRow);
				} else {
					int totalChildGroupCount = GroupInfo.GetTotalChildrenGroupCount(groupRow);
					for(int i = 1; i <= totalChildGroupCount; i++) {
						GroupRowInfo childGroupRow = GroupInfo[groupRow.Index + i];
						if(childGroupRow.Level - 1 == groupRow.Level)
							BuildVisibleIndexesCore(childGroupRow, expandAll, (expanded && groupRow.Expanded) || expandAll);
					}
				}
			}
		}
		protected void AddVisibleDataRows(GroupRowInfo rowInfo) {
			for(int i = 0; i < rowInfo.ChildControllerRowCount; i++)
				Add(rowInfo.ChildControllerRow + i);
		}
	}
}
